import tkinter as tk
from tkinter import messagebox
import json


class LinkedListNode:
    def __init__(self, data):
        self.data = data
        self.next = None


class LinkedList:
    def __init__(self):
        self.head = None

    def append(self, data):
        new_node = LinkedListNode(data)
        if not self.head:
            self.head = new_node
        else:
            current = self.head
            while current.next:
                current = current.next
            current.next = new_node

    def contains(self, data):
        current = self.head
        while current:
            if current.data == data:
                return True
            current = current.next
        return False

    def to_list(self):
        result = []
        current = self.head
        while current:
            result.append(current.data)
            current = current.next
        return result


class StudentNode:
    def __init__(self, username, interests, relations):
        self.username = username
        self.interests = interests
        self.relations = LinkedList()
        for friend in relations:
            self.relations.append(friend)


class SocialNetwork:
    def __init__(self):
        self.students = LinkedList()
        self.communities = {}

    def load_data(self, filename):
        with open(filename) as f:
            data = json.load(f)
            for s in data['students']:
                student = StudentNode(
                    username=s['username'],
                    interests=s['interests'],
                    relations=s['relations']
                )
                self.students.append(student)

    def _get_student(self, username):
        current = self.students.head
        while current:
            if current.data.username == username:
                return current.data
            current = current.next
        return None

    def get_friends(self, username):
        student = self._get_student(username)
        return student.relations.to_list() if student else []

    def find_shared_interests(self, username1, username2):
        s1 = self._get_student(username1)
        s2 = self._get_student(username2)
        if not s1 or not s2:
            return []

        common = []
        for interest in s1.interests:
            if interest in s2.interests and interest not in common:
                common.append(interest)
        return common

    def recommend_friends(self, username):
        recommendations = {}
        target = self._get_student(username)
        if not target:
            return []

        current = self.students.head
        while current:
            candidate = current.data
            if candidate.username != username and not target.relations.contains(candidate.username):
                common = self.find_shared_interests(username, candidate.username)
                if common:
                    recommendations[candidate.username] = common
            current = current.next

        sorted_rec = []
        while recommendations:
            max_user = max(recommendations, key=lambda k: len(recommendations[k]))
            sorted_rec.append((max_user, recommendations.pop(max_user)))
        return sorted_rec

    def add_friend(self, username1, username2):
        s1 = self._get_student(username1)
        s2 = self._get_student(username2)
        if s1 and s2:
            if not s1.relations.contains(username2):
                s1.relations.append(username2)
                s2.relations.append(username1)
                return True
        return False

    def filter_connections(self, interest):
        filtered_connections = []
        current = self.students.head
        while current:
            student = current.data
            if interest in student.interests:
                friends = self.get_friends(student.username)
                for friend in friends:
                    friend_node = self._get_student(friend)
                    if interest in friend_node.interests:
                        filtered_connections.append((student.username, friend))
            current = current.next
        return filtered_connections

    def create_community(self, community_name, members):
        self.communities[community_name] = members

    def join_community(self, community_name, username):
        if community_name in self.communities:
            if username not in self.communities[community_name]:
                self.communities[community_name].append(username)
                return True
        return False

    def leave_community(self, community_name, username):
        if community_name in self.communities:
            if username in self.communities[community_name]:
                self.communities[community_name].remove(username)
                return True
        return False

    def find_bridges(self):
        bridges = []
        community_list = list(self.communities.values())
        for i in range(len(community_list)):
            for j in range(i + 1, len(community_list)):
                for student in community_list[i]:
                    if student in community_list[j]:
                        bridges.append(student)
        return bridges


class SocialNetworkGUI:
    def __init__(self, root, social_network):
        self.root = root
        self.root.title("social networking system")
        self.social_network = social_network

        # 加载数据按钮
        self.load_button = tk.Button(root, text="load data", command=self.load_data)
        self.load_button.pack(pady=10)

        # 用户名输入框
        self.username_label = tk.Label(root, text="Enter user name:")
        self.username_label.pack()
        self.username_entry = tk.Entry(root)
        self.username_entry.pack()

        # 获取好友按钮
        self.get_friends_button = tk.Button(root, text="Get friends", command=self.get_friends)
        self.get_friends_button.pack(pady=10)

        # 查找共同兴趣输入框
        self.username1_label = tk.Label(root, text="Input the first user name:")
        self.username1_label.pack()
        self.username1_entry = tk.Entry(root)
        self.username1_entry.pack()

        self.username2_label = tk.Label(root, text="Enter the second user name:")
        self.username2_label.pack()
        self.username2_entry = tk.Entry(root)
        self.username2_entry.pack()

        # 查找共同兴趣按钮
        self.find_shared_interests_button = tk.Button(root, text="Find common interests",
                                                      command=self.find_shared_interests)
        self.find_shared_interests_button.pack(pady=10)

        # 推荐好友按钮
        self.recommend_friends_button = tk.Button(root, text="Recommend friends", command=self.recommend_friends)
        self.recommend_friends_button.pack(pady=10)

        # 添加好友输入框
        self.add_friend_username1_label = tk.Label(root, text="Enter the first user name to add friend:")
        self.add_friend_username1_label.pack()
        self.add_friend_username1_entry = tk.Entry(root)
        self.add_friend_username1_entry.pack()

        self.add_friend_username2_label = tk.Label(root, text="Enter the second user name to add friend:")
        self.add_friend_username2_label.pack()
        self.add_friend_username2_entry = tk.Entry(root)
        self.add_friend_username2_entry.pack()

        # 添加好友按钮
        self.add_friend_button = tk.Button(root, text="Add friend", command=self.add_friend)
        self.add_friend_button.pack(pady=10)

        # 筛选连接输入框
        self.filter_interest_label = tk.Label(root, text="Enter the interest to filter connections:")
        self.filter_interest_label.pack()
        self.filter_interest_entry = tk.Entry(root)
        self.filter_interest_entry.pack()

        # 筛选连接按钮
        self.filter_connections_button = tk.Button(root, text="Filter connections", command=self.filter_connections)
        self.filter_connections_button.pack(pady=10)

        # 创建社区输入框
        self.create_community_name_label = tk.Label(root, text="Enter the community name to create:")
        self.create_community_name_label.pack()
        self.create_community_name_entry = tk.Entry(root)
        self.create_community_name_entry.pack()

        self.create_community_members_label = tk.Label(root, text="Enter the members (comma separated) to create community:")
        self.create_community_members_label.pack()
        self.create_community_members_entry = tk.Entry(root)
        self.create_community_members_entry.pack()

        # 创建社区按钮
        self.create_community_button = tk.Button(root, text="Create community", command=self.create_community)
        self.create_community_button.pack(pady=10)

        # 加入社区输入框
        self.join_community_name_label = tk.Label(root, text="Enter the community name to join:")
        self.join_community_name_label.pack()
        self.join_community_name_entry = tk.Entry(root)
        self.join_community_name_entry.pack()

        self.join_community_username_label = tk.Label(root, text="Enter the user name to join community:")
        self.join_community_username_label.pack()
        self.join_community_username_entry = tk.Entry(root)
        self.join_community_username_entry.pack()

        # 加入社区按钮
        self.join_community_button = tk.Button(root, text="Join community", command=self.join_community)
        self.join_community_button.pack(pady=10)

        # 离开社区输入框
        self.leave_community_name_label = tk.Label(root, text="Enter the community name to leave:")
        self.leave_community_name_label.pack()
        self.leave_community_name_entry = tk.Entry(root)
        self.leave_community_name_entry.pack()

        self.leave_community_username_label = tk.Label(root, text="Enter the user name to leave community:")
        self.leave_community_username_label.pack()
        self.leave_community_username_entry = tk.Entry(root)
        self.leave_community_username_entry.pack()

        # 离开社区按钮
        self.leave_community_button = tk.Button(root, text="Leave community", command=self.leave_community)
        self.leave_community_button.pack(pady=10)

        # 查找桥梁按钮
        self.find_bridges_button = tk.Button(root, text="Find bridges", command=self.find_bridges)
        self.find_bridges_button.pack(pady=10)

        # 结果显示框
        self.result_text = tk.Text(root, height=10, width=50)
        self.result_text.pack(pady=10)

    def load_data(self):
        try:
            self.social_network.load_data("resources\students.json")
            messagebox.showinfo("Success", "Data loaded successfully!")
        except Exception as e:
            messagebox.showerror("Error", f"Data loading failed: {e}")

    def get_friends(self):
        username = self.username_entry.get()
        friends = self.social_network.get_friends(username)
        self.result_text.delete(1.0, tk.END)
        if friends:
            self.result_text.insert(tk.END, f"{username} Friends of: {', '.join(friends)}")
        else:
            self.result_text.insert(tk.END, f"Not found {username} Or this user has no friends.")

    def find_shared_interests(self):
        username1 = self.username1_entry.get()
        username2 = self.username2_entry.get()
        common_interests = self.social_network.find_shared_interests(username1, username2)
        self.result_text.delete(1.0, tk.END)
        if common_interests:
            self.result_text.insert(tk.END, f"{username1} and {username2} Common interests are.: {', '.join(common_interests)}")
        else:
            self.result_text.insert(tk.END, f"{username1} and {username2} There is no common interest or the user does not exist.")

    def recommend_friends(self):
        username = self.username_entry.get()
        recommendations = self.social_network.recommend_friends(username)
        self.result_text.delete(1.0, tk.END)
        if recommendations:
            self.result_text.insert(tk.END, f"{username} recommended friends have:\n")
            for friend, interests in recommendations:
                self.result_text.insert(tk.END, f"{friend}: {', '.join(interests)}\n")
        else:
            self.result_text.insert(tk.END, f"Not found {username} Or there is no recommended friend.")

    def add_friend(self):
        username1 = self.add_friend_username1_entry.get()
        username2 = self.add_friend_username2_entry.get()
        success = self.social_network.add_friend(username1, username2)
        self.result_text.delete(1.0, tk.END)
        if success:
            self.result_text.insert(tk.END, f"{username1} and {username2} are now friends.")
        else:
            self.result_text.insert(tk.END, f"Failed to add {username1} and {username2} as friends.")

    def filter_connections(self):
        interest = self.filter_interest_entry.get()
        connections = self.social_network.filter_connections(interest)
        self.result_text.delete(1.0, tk.END)
        if connections:
            self.result_text.insert(tk.END, f"Connections related to {interest}:\n")
            for connection in connections:
                self.result_text.insert(tk.END, f"{connection[0]} - {connection[1]}\n")
        else:
            self.result_text.insert(tk.END, f"No connections found related to {interest}.")

    def create_community(self):
        community_name = self.create_community_name_entry.get()
        members_str = self.create_community_members_entry.get()
        members = members_str.split(',')
        members = [member.strip() for member in members]
        self.social_network.create_community(community_name, members)
        self.result_text.delete(1.0, tk.END)
        self.result_text.insert(tk.END, f"Community {community_name} created with members: {', '.join(members)}")

    def join_community(self):
        community_name = self.join_community_name_entry.get()
        username = self.join_community_username_entry.get()
        success = self.social_network.join_community(community_name, username)
        self.result_text.delete(1.0, tk.END)
        if success:
            self.result_text.insert(tk.END, f"{username} joined community {community_name}.")
        else:
            self.result_text.insert(tk.END, f"Failed to join {username} to community {community_name}.")

    def leave_community(self):
        community_name = self.leave_community_name_entry.get()
        username = self.leave_community_username_entry.get()
        success = self.social_network.leave_community(community_name, username)
        self.result_text.delete(1.0, tk.END)
        if success:
            self.result_text.insert(tk.END, f"{username} left community {community_name}.")
        else:
            self.result_text.insert(tk.END, f"Failed to remove {username} from community {community_name}.")

    def find_bridges(self):
        bridges = self.social_network.find_bridges()
        self.result_text.delete(1.0, tk.END)
        if bridges:
            self.result_text.insert(tk.END, f"Bridges between communities: {', '.join(bridges)}")
        else:
            self.result_text.insert(tk.END, "No bridges found between communities.")


if __name__ == "__main__":
    root = tk.Tk()
    social_network = SocialNetwork()
    app = SocialNetworkGUI(root, social_network)
    root.mainloop()
    